﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Xml.Linq;
using log4net;
using System.Linq;

namespace GenerateDB
{
    /// <summary>
    /// Класс для разбора xml описания журнала.
    /// </summary>
    class ParserXMLJournal
    {
        private static readonly ILog _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        private string _xmlFile;
        private Settings _settings;
        private XDocument _loadXml;
        private XNamespace _xmlNamespace;

        /// <summary>
        /// Разбор xml описания журнала
        /// </summary>
        /// <param name="filename">Xml файл</param>
        public ParserXMLJournal(string filename)
        {
            this.Init(filename);
        }

        /// <summary>
        /// Функция инициализации класса.
        /// </summary>
        /// <param name="filename">Имя xml файла</param>
        private void Init(string filename)
        {
            _xmlFile = filename;
            _settings = new Settings();
            _xmlNamespace = _settings.TargetNamespace;
            try
            {
                _loadXml = XDocument.Load(_xmlFile);
            }
            catch (XmlException ex)
            {
                _log.Error("Ошибка загрузки xml файла описания журнала", ex);
                throw ex;
            }
        }

        /// <summary>
        /// Разбор XML файла с описанием журнала.
        /// </summary>
        /// <returns>Возвращает данные журнала.</returns>
        public Journal ParseJournal()
        {
            Journal res = new Journal();
            res.Name = this.ParseNameJournal();
            //res.Encryption = this.ParserEncryption();
            res.Columns = this.ParseColumns();
            return res;
        }

        /// <summary>
        /// Функция партит имя журнала из xml описания.
        /// </summary>
        /// <returns>Возвращает имя журнала</returns>
        private string ParseNameJournal()
        {
            return this.GetTagValue(_settings.TagName);
        }

        private string GetTagValue(string tag)
        {
            try
            {
                var result = (from data in _loadXml.Descendants(_xmlNamespace + _settings.MainTag)
                              select data.Element(_xmlNamespace + tag).Value).First();
                return result;
            }
            catch (XmlException ex)
            {
                string errorMsg = String.Format("Ошибка разбора атрибута '{0}'", tag);
                _log.Error(errorMsg, ex);
                throw ex;
            }
        }

        private bool ParserEncryption()
        {
            return System.Convert.ToBoolean(this.GetTagValue(_settings.TagEncryption));
        }

        /// <summary>
        /// Функция парсит колонки журнала из xml описания.
        /// </summary>
        /// <returns>Возвращает список колонок журнала.</returns>
        private List<ColumnInfo> ParseColumns()
        {
            try
            {
                var result = (from data in _loadXml.Descendants(_xmlNamespace + _settings.MainTag)
                              from columns in data.Descendants(_xmlNamespace + _settings.TagColumns).Elements()
                              select new ColumnInfo
                              {
                                  Name = columns.Element(_xmlNamespace + _settings.TagColumnName).Value,
                                  NameRus = columns.Element(_xmlNamespace + _settings.TagNameRus).Value,
                                  Type = columns.Element(_xmlNamespace + _settings.TagColumnType).Value,
                                  Description = columns.Element(_xmlNamespace + _settings.TagColumnDescription).Value
                              }).ToList();

                return result;
            }
            catch (XmlException ex)
            {
                _log.Error("Ошибка разбора колонок журнала.", ex);
                throw ex;
            }
        }
    }
}
